実際のパイプラインでの bind と map の利用
LT;DR
入力が複数ある関数を合成するには、別途対策が必要
code:fsharp
type AcknowledgeOrder =
PricedOrder -> OrderAcknowledgmentSent option
type CreateEvents =
PricedOrder -> OrderAcknowledgmentSent option -> PlaceOrderEvent list
hr.icon
ただし、Async や依存関係は無視する
各ステップの型定義 は以下のように
「注文の検証」と「注文の価格計算」は失敗する可能性があるので、Result を返す
code:fsharp
type ValidateOrder =
UnvalidatedOrder -> Result<ValidatedOrder, ValidationError>
type PriceOrder =
ValidatedOrder -> Result<PricedOrder, PricingError>
一方、「注文の確認」と「イベントの作成」は常に成功するので Result を返さない
code:fsharp
type AcknowledgeOrder =
PricedOrder -> OrderAcknowledgmentSent option
type CreateEvents =
PricedOrder -> OrderAcknowledgmentSent option -> PlaceOrderEvent list
合成フロー
1. ValidationError と PricingError に互換性は無いので、それぞれをケースに持つ 選択型 を作成する code:fsharp
type PlaceOrderError =
| Validation of ValidationError
| Pricing of PricingError
2. mapError で合成可能な関数にする
code:fsharp
let validateOrderApdated input =
input
|> validateOrder
|> Result.mapError PlaceOrderError.Validation
let priceOrderAdapted input =
input
|> priceOrder
|> Result.mapError PlaceOrderError.Pricing
3. bind で合成する
AcknowledgeOrder と CreateEvents は Result を返さないので、map を用いて Result を返すように変換する
code:fsharp
// val placeOrder : UnvalidatedOrder -> Result<PlaceOrderEvent list, PlaceOrderError>
let placeOrder unvalidatedOrder =
unvalidatedOrder
|> validateOrderAdapted
|> Result.bind priceOrderAdapted
|> Result.map acknowledgeOrder
|> Result.map createEvents
問題点
AcknowledgeOrder の出力が CreateEvents の入力と一致していないので、上記のコードはコンパイルエラーを起こす
AcknowledgeOrder の出力: Result<OrderAcknowledgmentSent option, PlaceOrderError>
CreateEvents の入力: PricedOrder -> OrderAcknowledgmentSent option